package cn.ichiva;

import cn.ichiva.common.ThreadContent;
import cn.ichiva.common.jwt.JWTParser;
import cn.ichiva.service.RedisService;
import cn.ichiva.vo.WSRequest;
import cn.ichiva.vo.WSResponse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.websocket.WsSession;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 多实例,连接绑定实列
 */
@Slf4j
@ServerEndpoint(value = "/{token}")
public class WSApi implements ApplicationContextAware {
    private static ConcurrentHashMap<Session,Object> onlineMap = new ConcurrentHashMap<>();
    private static RedisService redisService;
    private static JWTParser jwtParser;
    private String account;

    @OnOpen
    public void onOpen(Session session,@PathParam("token") String token) {
        log.info("token={}",token);
        try {
            String json = jwtParser.parse(token);
            this.account = JSON.parseObject(json).getString("account");
            log.info("[接入]{}",this.account);
            onlineMap.put(session,System.currentTimeMillis());
            log.info("当前在线人数:{}",onlineMap.size());
        }catch (Exception e){
            log.warn("链接失败",e);
            try {
                session.close();
            } catch (IOException ex) {
                log.error("session close error",e);
            }
        }
    }

    @OnClose
    public void onClose(Session session) {
        onlineMap.remove(session);
        int count = onlineMap.size();
        log.info("[关闭]当前在线人数：{}", count);
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("[{}]的消息:{}", account, message);
        WSRequest vo = JSON.parseObject(message, WSRequest.class);
        ThreadContent.put("account",account);
        try{
            Object res = redisService.exec(vo);
            if(vo.getId() != 0){
                WSResponse msg = WSResponse.builder()
                            .id(vo.getId())
                            .code(200)
                            .data(res)
                            .build();

                sendMessage(JSON.toJSONString(msg),session);
            }

        }catch (Exception e){
            log.warn("redisService error",e);
            WSResponse err = WSResponse.builder()
                    .id(vo.getId())
                    .code(500)
                    .msg(e.getMessage())
                    .build();

            sendMessage(JSON.toJSONString(err),session);
        }finally {
            ThreadContent.clear();
        }
    }

    @OnError
    public void onError(Session session, Throwable error)  {
        log.error("链接错误",error);
        try {
            session.close();
        }catch (Exception e){
            log.error("session close error",e);
        }
    }

    /**
     * 服务端发送消息给客户端
     */
    private static void sendMessage(String message, Session toSession) {
        try {
            toSession.getBasicRemote().sendText(message);
        } catch (Exception e) {
            log.error("服务端发送消息给客户端失败：{}", e);
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        redisService = applicationContext.getBean(RedisService.class);
        jwtParser = applicationContext.getBean(JWTParser.class);
    }
}